package com.medical.medicalmodulecommon.minio;

import com.medical.medicalmodulecommon.api.FileService;
import com.medical.medicalmodulecommon.minio.MinioConfig;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.DeleteObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;

@Slf4j
@Service
public class MinioServiceImpl implements FileService {

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinioConfig minioConfig;

    @Override
    public String uploadFile(InputStream inputStream, String objectName,
                             String contentType, long fileSize) {
        try {
            // 确保存储桶存在
            createBucketIfNotExists();

            // 上传文件
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object(objectName)
                    .stream(inputStream, fileSize, -1)
                    .contentType(contentType)
                    .build());

            log.info("文件上传成功: {}/{}", minioConfig.getBucketName(), objectName);
            return getFileUrl(objectName);
        } catch (Exception e) {
            log.error("文件上传失败", e);
            throw new RuntimeException("文件上传失败", e);
        }
    }
    /**
     * 上传文件 （自动处理MultipartFile）
     */
    @Override
    public String uploadFile(MultipartFile file, String objectName) {
        try {
            // 自动处理文件流转换
            return uploadFile(
                    file.getInputStream(),
                    objectName,
                    file.getContentType(),
                    file.getSize()
            );
        } catch (Exception e) {
            log.error("文件上传失败", e);
            throw new RuntimeException("文件上传失败: " + e.getMessage(), e);
        }
    }

    /**
     * 上传文件 - （使用原始文件名）
     */
    @Override
    public String uploadFile(MultipartFile file) {
        // 使用原始文件名作为对象名称
        String objectName = file.getOriginalFilename();
        return uploadFile(file, objectName);
    }

    @Override
    public InputStream downloadFile(String objectName) {
        try {
            return minioClient.getObject(GetObjectArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object(objectName)
                    .build());
        } catch (Exception e) {
            log.error("文件下载失败", e);
            throw new RuntimeException("文件下载失败", e);
        }
    }

    @Override
    public String getFileUrl(String objectName) {
        try {
            if (objectName.startsWith("/")) {
                objectName = objectName.substring(1);
            }
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object(objectName)
                    .method(Method.GET)
                    .expiry(60 * 60) // 1小时过期
                    .build());
        } catch (Exception e) {
            log.error("获取文件URL失败", e);
            throw new RuntimeException("获取文件URL失败", e);
        }
    }

    @Override
    public boolean removeObject(String objectName) {
        try {
            minioClient.removeObject(RemoveObjectArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object(objectName)
                    .build());
            log.info("文件删除成功: {}/{}", minioConfig.getBucketName(), objectName);
            return true;
        } catch (Exception e) {
            log.error("文件删除失败", e);
            return false;
        }
    }

    @Override
    public boolean objectExist(String objectName) {
        try {
            minioClient.statObject(StatObjectArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object(objectName)
                    .build());
            return true;
        } catch (Exception e) {
            log.error("判断文件是否存在失败", e);
            return false;
        }
    }

    @Override
    public Object getObjectInfo(String objectName) {
        try {
            return minioClient.statObject(StatObjectArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object(objectName)
                    .build());
        } catch (Exception e) {
            log.error("获取文件信息失败", e);
            throw new RuntimeException("获取文件信息失败", e);
        }
    }

    /**
     * 创建存储桶（如果不存在）
     */
    private void createBucketIfNotExists() {
        try {
            boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .build());
            if (!isExist) {
                minioClient.makeBucket(MakeBucketArgs.builder()
                        .bucket(minioConfig.getBucketName())
                        .build());
                log.info("存储桶创建成功: {}", minioConfig.getBucketName());
            }
        } catch (Exception e) {
            log.error("创建存储桶失败", e);
            throw new RuntimeException("创建存储桶失败", e);
        }
    }

    /**
     * 批量删除文件（内部方法）
     */
    public boolean removeObjects(List<String> objectNames) {
        try {
            List<DeleteObject> deleteObjects = new LinkedList<>();
            objectNames.forEach(objectName -> deleteObjects.add(new DeleteObject(objectName)));

            minioClient.removeObjects(RemoveObjectsArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .objects(deleteObjects)
                    .build());
            return true;
        } catch (Exception e) {
            log.error("批量删除文件失败", e);
            return false;
        }
    }
    @Override
    public ResponseEntity<Resource> downloadFileAsResponse(String objectName) {
        try {
            // 检查文件是否存在
            if (!objectExist(objectName)) {
                log.warn("文件不存在: {}", objectName);
                return ResponseEntity.notFound().build();
            }

            // 获取文件流
            InputStream inputStream = downloadFile(objectName);

            // 提取文件名
            String filename = extractFileName(objectName);

            // 获取文件信息设置Content-Type
            StatObjectResponse stat = minioClient.statObject(StatObjectArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object(objectName)
                    .build());

            // 创建资源
            InputStreamResource resource = new InputStreamResource(inputStream);

            // 构建响应头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentDispositionFormData("attachment", filename);
            headers.setContentType(MediaType.parseMediaType(stat.contentType() != null ? stat.contentType() : "application/octet-stream"));
            headers.setContentLength(stat.size());
            headers.add("X-File-Name", filename);
            headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
            headers.add("Pragma", "no-cache");
            headers.add("Expires", "0");

            log.info("文件下载准备完成: {}, 文件名: {}", objectName, filename);

            return ResponseEntity.ok()
                    .headers(headers)
                    .body(resource);

        } catch (Exception e) {
            log.error("文件下载失败: {}", objectName, e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }

    /**
     * 从对象名称中提取文件名
     */
    private String extractFileName(String objectName) {
        if (objectName.contains("/")) {
            return objectName.substring(objectName.lastIndexOf("/") + 1);
        }
        return objectName;
    }
}